﻿using System;
using System.IO;

namespace Sanjeet.FastCopy.FileCopyLogic.Design1
{
    /// <summary>
    /// 
    /// </summary>
    public class FileUtility : IAsyncable, IFileUtility
    {
        private const string DefaultSearchPattern = "*.*";
        private IAsyncableData asyncData;
        private string destination;
        private FileInfo[] filesInfo;
        private string searchPattern;
        private string source;
        private bool subfolder;

        #region IAsyncable Members

        /// <summary>
        /// 
        /// </summary>
        public void StartAsync()
        {
            filesInfo = GetFiles(source, searchPattern);
            CopyFiles(destination, filesInfo);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        public void StartAsync(IAsyncableData data)
        {
            var files = data.Input as FileInfo[];
            CopyFiles(destination, files);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnProgressChanged(object sender, EventArgs e)
        {
            if (ProgressChanged == null) return;
            ProgressChanged(sender, e);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnCompleted(object sender, EventArgs e)
        {
            if (Completed == null) return;
            Completed(sender, e);
        }

        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<EventArgs> ProgressChanged;

        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<EventArgs> Completed;

        #endregion

        #region IFileUtility Members

        public string Source
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        public string SearchPattern
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        public string Destination
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        public FileInfo[] FilesInfo
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool Overwrite { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public bool SubFolder
        {
            get { return subfolder; }
            set { subfolder = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="searchPattern"></param>
        /// <returns></returns>
        public FileInfo[] GetFiles(string source, string searchPattern)
        {
            if (string.IsNullOrEmpty(source)) throw new ArgumentException("Invalid source");
            if (string.IsNullOrEmpty(searchPattern)) searchPattern = DefaultSearchPattern;
            var directory = new DirectoryInfo(Path.GetDirectoryName(source));
            if (!Directory.Exists(directory.FullName)) throw new ArgumentException("Invalid source directory");
            FileInfo[] files = null;
            files = subfolder
                        ? directory.GetFiles(searchPattern, SearchOption.AllDirectories)
                        : directory.GetFiles(searchPattern, SearchOption.TopDirectoryOnly);
            return files;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="destination"></param>
        /// <param name="files"></param>
        public void CopyFiles(string destination, FileInfo[] files)
        {
            foreach (FileInfo file in files)
            {
                if (!File.Exists(file.FullName))
                    throw new ArgumentException(string.Format("File: '{0}' not found", file.FullName));
                string directoryName = Path.GetDirectoryName(destination);
                if (!Directory.Exists(directoryName)) Directory.CreateDirectory(directoryName);
                Copy(file.FullName, Path.Combine(Path.GetDirectoryName(destination), file.Name));
            }
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        public void Copy(string source, string destination)
        {
            using (var sourceFile = new FileStream(source, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                using (
                    var destinationFile = new FileStream(destination, FileMode.Create, FileAccess.ReadWrite,
                                                         FileShare.ReadWrite))
                {
                    var contents = new byte[sourceFile.Length];
                    sourceFile.Read(contents, 0, (int) sourceFile.Length);
                    destinationFile.Write(contents, 0, (int) sourceFile.Length);
                }
            }
        }
    }
}